package com.yunlongn.common.json.jackson.factory.impl;

import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import com.yunlongn.common.json.jackson.factory.IJacksonExclusion;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class JacksonExclusionTransientImpl extends SimpleFilterProvider implements IJacksonExclusion {

    @JsonFilter("myFilter")
    public interface MyFilter {
    }

    public JacksonExclusionTransientImpl() {

    }
    private static Set<Class<?>> strategys = new HashSet<>();


    /**
     * 缓存某类是否需要拥有该策略 例如： User 是否有 transient 字段。有的话缓存起来
     */
    private static Map<Class<?>, JacksonExclusionTransientImpl> STRATEGY_MAP = new HashMap<>();

    private static JacksonExclusionTransientImpl createStrategy(Class<?> cla) {
        // 忽略被transient声明的字段
        Field[] fields = cla.getDeclaredFields();
        StringBuilder ignoreFields = new StringBuilder();
        for (Field field : fields) {
            if ((field.getModifiers() & Modifier.TRANSIENT) == Modifier.TRANSIENT) {
                if (ignoreFields.length() > 0) {
                    ignoreFields.append(",");
                }
                ignoreFields.append(field.getName());
            }
        }
        // 指定Class 并无 transient 字段
        if (ignoreFields.length() == 0) {
            return null;
        }
        String ignoreStr = ignoreFields.toString();
        JacksonExclusionTransientImpl jacksonExclusionStrategy = new JacksonExclusionTransientImpl();
        // 调用 SimpleBeanPropertyFilter 的 serializeAllExcept 方法 或 重写 SimpleBeanPropertyFilter 的 serializeAsField 方法过滤属性
        jacksonExclusionStrategy.addFilter("myFilter", SimpleBeanPropertyFilter.serializeAllExcept(ignoreStr.split(",")));
        return jacksonExclusionStrategy;
    }

    public static JacksonExclusionTransientImpl getInstance(final Class<?> cla) {
        // 判断类是否需已经缓存有策略
        JacksonExclusionTransientImpl strategy = STRATEGY_MAP.get(cla);
        if (!STRATEGY_MAP.containsKey(cla)) {
            // 相同类进来会进入一个锁
            synchronized (cla) {
                if (!STRATEGY_MAP.containsKey(cla)) {
                    strategy = createStrategy(cla);
                    Map<Class<?>, JacksonExclusionTransientImpl> newMap = new HashMap<>(STRATEGY_MAP);
                    newMap.put(cla, strategy);
                    STRATEGY_MAP = newMap;
                }
            }
        }
        return strategy;
    }

    public void addExclusionStrategy(final Class<?> cla, ObjectMapper objectMapperSub) {
        // 判断类是否需已经缓存有策略
        JacksonExclusionTransientImpl instance = getInstance(cla);
        // 如果为空，说明class 不需要进行策略化
        if (instance == null) {
            return;
        }
        if (strategys.contains(cla)) {
            return;
        }
        synchronized (objectMapperSub) {
            if (strategys.contains(cla)) {
                return;
            }
            Set<Class<?>> newSet = new HashSet<>();
            newSet.add(cla);
            strategys = newSet;
            objectMapperSub.setFilterProvider(instance);
            // 将@JsonFilter 作用于 java 对象上
            objectMapperSub.addMixIn(cla, JacksonExclusionTransientImpl.MyFilter.class);
        }
    }

}